'''
Created on Jun 14, 2009

@author: trevor
'''

import sys,math,random,operator,os
import pp

 
def SA(MyObj,module_name,t0,cool):
        module = __import__(module_name)
        for numSame in range(0,100):
            neighbor = module.Mutator(MyObj)
        #always accept good changes
            if module.Comparor(neighbor,MyObj):
                MyObj = neighbor
                numSame = 0
            else:
                r = random.random()
                e = math.exp( -(module.Differencer(neighbor,MyObj) / t0) )
                if r < e:
                    MyObj = neighbor
                    numSame = 0
            t0 = t0 * cool
        return MyObj


if __name__ == '__main__':
    
    #set up ParallelPython stuff
    ppservers=("*",)
    remoteCPUS = 0
    localCPUS = 2
    numCPUS=remoteCPUS + localCPUS
    job_server = pp.Server(ppservers=ppservers,ncpus=localCPUS)
    print "Starting Module_SA with", numCPUS, " total workers"
    
    #import user's modules
    module_name = sys.argv[1]
    module = __import__(module_name)
    
    #create an initial version of the user's object
    CurObj = module.Creator()
    print "INITIAL CONFIG: ", module.Printable(CurObj)
    
    ####CONFIG
    temperature = 10
    cool = .95
    ####END_CONFIG
    
    
    #submit a few jobs to the CPUs
    curCPU = 0
    jobs = dict()
    for i in range(0,numCPUS):
        jobs[i] = job_server.submit(SA, (CurObj,module_name,temperature,cool),(), ("math","random"))
    
    sameCount = 0
    flag = True
    while flag:
        if(jobs[curCPU].finished):
            #When a job is completed, grab its result, evaluate it to see if the new value is better
            #and either keep it or toss it. Then restart this processor on the current best result
            result = jobs[curCPU]()
            print "Result value from CPU #:", curCPU, " was: ", module.Printable(result)
            if module.Comparor(result,CurObj):
                CurObj = result
                sameCount = 0
            else:
                sameCount = sameCount + 1
            print "Giving job to CPU #: ", curCPU, " with value of: ", module.Printable(CurObj)
            jobs[curCPU] = job_server.submit(SA, (CurObj,module_name,temperature,cool),(), ("math","random"))

        if sameCount > 50:
            #If we have 50 of the same answer, we quit
            flag = False
        curCPU = operator.mod((curCPU + 1),numCPUS)
        
    job_server.print_stats()
            
    
    